pub mod asyncs;

use std::collections::HashMap;
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::ops::Add;
use std::{io, thread};
use crate::{flags, JaegerTracing};
use crate::codes::tcp::{TcpData};
use crossbeam_channel::{ Receiver, Sender};
use std::thread::sleep;
use std::time::Duration;
use crate::util::cacher::Cacher;

pub struct TcpClient {
    listener:TcpListener,
    stream:Option<TcpStream>,
    dict_fn:HashMap<String,Cacher>,
    response:HashMap<String,Option<Sender<Vec<u8>>>>,
}

impl TcpClient {
    pub fn new(port:u32) -> Self {
        let mut addr = String::from("0.0.0.0");
        addr.push(':');
        addr = addr.add(port.to_string().as_str());

        let listener = TcpListener::bind(addr).unwrap();

        TcpClient{
            listener,
            dict_fn: Default::default(),
            stream:None,
            response: Default::default(),
        }
    }
}

impl Clone for TcpClient{
    fn clone(&self) -> Self {
        TcpClient{
            listener: self.listener.try_clone().unwrap(),
            stream: Some(self.stream.as_ref().unwrap().try_clone().unwrap()),
            dict_fn: self.dict_fn.clone(),
            response: self.response.clone()
        }
    }
}


impl TcpClient {
    pub fn run(&mut self) {
        for res in self.listener.incoming() {
            if let Ok(mut stream) = res {
                let res = self.list_by_stream(&mut stream);
                if let Err(e) = res {
                   println!("tcp client err:{}",e);
                   continue;
                }
                self.stream = Some(stream);
            }
            break;
        }

        println!("begin loop");
        loop {
            self.read().unwrap();
        }

    }

    pub fn add_fn<F>(&mut self, tag: String, f:F)
        where F:FnMut(Vec<u8>) -> Vec<u8> + 'static
    {
        let mut cacher = Cacher::new(f);
        self.dict_fn.insert(tag,cacher);
    }

    pub fn write(&mut self, tag:&'static str, data:Vec<u8>) -> Result<Vec<u8>, String> {
        let tcp_data = TcpData::encode(tag.to_string(),data);
        let id = tcp_data.id();
        let res = self.stream.as_mut().unwrap().write(tcp_data.bytes().as_slice());
        match res {
            Ok(_) => {
                let (sender, receive) = crossbeam_channel::bounded(50);
                self.response.insert(id, Some(sender));

                let recv = receive.recv();
                match recv {
                    Ok(data) => {
                        Ok(data)
                    },
                    Err(e) => { Err(e.to_string()) }
                }
            },
            Err(e) => { Err(e.to_string()) }
        }
    }

    fn list_by_stream(&self, stream:&mut TcpStream) -> Result<(),String> {
        let tcp_data = TcpData::encode("hi".to_string(),Vec::new());
        let res = stream.write(tcp_data.bytes().as_slice());
        if let Err(e) = res {
            return Err(e.to_string());
        }

        let mut buf = [0;1024*20];
        let hi_data = stream.read(&mut buf);
        if let Err(e) = hi_data {
            return Err(e.to_string());
        }

        if hi_data.unwrap() > 0 {
            return Ok(());
        }

        Err(String::from("error"))
    }


    fn read(&mut self) -> Result<(),String> {
        let mut buf = [0;1024*20];
        let res = self.stream.as_mut().unwrap().read(&mut buf);
        match res {
            Ok(data)=> {
                let d = &buf[..data];
                println!("{}",String::from_utf8(d.to_vec()).unwrap());
                let new = TcpData::decode(d.to_vec());
                if new.tag().is_response() {
                    let id = new.id();
                    let sender = self.response.get_mut(&*id).unwrap().as_mut().unwrap();
                    sender.send(new.data().clone()).unwrap();
                } else {
                    if new.tag().string() == "probe" {
                        let response_data = new.response_data(vec![1]);
                        let write_res = self.stream.as_mut().unwrap().write(response_data.bytes().as_slice());
                        if let Err(e) = write_res {
                            return Err(e.to_string());
                        }
                    } else {
                        let op = self.dict_fn.get_mut(&*new.tag().string());
                        match op {
                            Some(f) => {
                                let mut response = f.exec(new.data().clone());
                                let res_data =  new.response_data(response);
                                let write_res = self.stream.as_mut().unwrap().write(res_data.bytes().as_slice());
                                if let Err(e) = write_res {
                                    return Err(e.to_string());
                                }
                            },
                            None => {
                                return Err(String::from("function not found"));
                            }
                        }
                    }
                }

                return Ok(());
            },
            Err(e) => {return Err(e.to_string());}
        }
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test () {

    }
}
